package com.seovic.identity;


import java.util.concurrent.CountDownLatch;

import java.util.Set;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;


/**
 * Multi-threaded test client for {@link IdentityGenerator} implementations.
 *
 * @author Aleksandar Seovic  2008.11.24
 */
@SuppressWarnings({"unchecked", "EmptyCatchBlock"})
public class IdentityGeneratorClient
    {
    // ---- constructors ----------------------------------------------------

    /**
     * Construct IdentityGeneratorClient instance.
     *
     * @param generator  identity generator to test
     */
    public IdentityGeneratorClient(IdentityGenerator generator)
        {
        this.generator = generator;
        }


    // ---- public methods --------------------------------------------------

    /**
     * Starts specified number of identity generation threads, each of which
     * should generate the specified number of identities.
     *
     * @param numThreads     number of identity generation threads to start
     * @param numIdentities  number of identities to generate (per thread)
     *
     * @return a set of identities generated by all threads
     */
    public Set generateIdentities(int numThreads, int numIdentities)
        {
        Set identities = Collections.synchronizedSet(new HashSet());

        try 
            {
            CountDownLatch start = new CountDownLatch(1);
            CountDownLatch done  = new CountDownLatch(numThreads);

            for (int i = 0; i < numThreads; i++)
                {
                new IdentityGeneratorThread(identities, numIdentities, start, done).start();
                }

            start.countDown();
            done.await();
            }
        catch (InterruptedException ignore)
            {
            }

        return identities;
        }


    // ---- inner class: IdentityGeneratorThread ----------------------------

    /**
     * Generates specified number of identities and adds them to the result set.
     */
    class IdentityGeneratorThread
            extends Thread
        {
        private final Set            identities;
        private final int            numIdentities;
        private final Random         randomizer;
        private final CountDownLatch start;
        private final CountDownLatch done;

        public IdentityGeneratorThread(Set identities, int numIdentities,
                                       CountDownLatch start, CountDownLatch done)
            {
            this.identities    = identities;
            this.numIdentities = numIdentities;
            this.randomizer    = new Random();
            this.start         = start;
            this.done          = done;
            }

        public void run()
            {
            try
                {
                start.await();
                for (int i = 0; i < numIdentities; i++)
                    {
                    identities.add(generator.generateIdentity());
                    try
                        {
                        Thread.sleep(randomizer.nextInt(10));
                        }
                    catch (InterruptedException e)
                        {
                        }
                    }
                done.countDown();
                }
            catch (InterruptedException ignore)
                {
                }
            }
        }


    // ---- data members ----------------------------------------------------

    /**
     * IdentityGenerator to test.
     */
    private IdentityGenerator generator;
    }
